package com.oro.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

public class ListMap<K, V> implements List<Pair<K, V>> {

	private List<Pair<K, V>> list = new ArrayList<Pair<K, V>>();

	@Override
	public void add(int index, Pair<K, V> element) {
		list.add(index, element);

	}

	/**
	 * Add a new Pair without checking for duplicate keys.
	 * 
	 * @param key
	 * @param value
	 * @return true (as per the general contract of Collection.add).
	 */
	public boolean add(K key, V value) {
		return list.add(new Pair<K, V>(key, value));
	}

	/**
	 * Add a new Pair without checking for duplicate keys.
	 * 
	 * @param e
	 *            the Pair to add
	 * @return true (as per the general contract of Collection.add).
	 */

	@Override
	public boolean add(Pair<K, V> e) {
		// list confronta l'esistenza con equals, quindi ok.
		return list.add(e);
	}

	@Override
	public boolean addAll(Collection<? extends Pair<K, V>> c) {
		return list.addAll(c);
	}

	@Override
	public boolean addAll(int index, Collection<? extends Pair<K, V>> c) {
		return list.addAll(index, c);
	}

	@Override
	public void clear() {
		list = new ArrayList<Pair<K, V>>();
	}

	@Override
	public boolean contains(Object o) {
		return list.contains(o);
	}

	@Override
	public boolean containsAll(Collection<?> c) {
		return list.containsAll(c);
	}

	public boolean containsKey(K key) {
		for (Pair<K, V> pair : list)
			if (pair.getKey().equals(key))
				return true;
		return false;
	}

	public boolean containsValue(Object arg0) {
		for (Pair<K, V> pair : list)
			if (pair.getValue().equals(arg0))
				return true;
		return false;
	}

	public Set<Map.Entry<K, V>> entrySet() {
		Set<Map.Entry<K, V>> set = new LinkedHashSet<Map.Entry<K, V>>();
		for (Pair<K, V> pair : list) {
			set.add(pair);
		}
		return set;
	}

	@Override
	public Pair<K, V> get(int index) {
		return list.get(index);
	}

	/**
	 * 
	 * @param key
	 * @return the value corresponding to the given key
	 */
	@SuppressWarnings("unchecked")
	public V get(Object key) {
		return getEntry((K) key).getValue();
	}

	/**
	 * 
	 * @param key
	 * @return the Pair that has the given key
	 */
	public Pair<K, V> getEntry(K key) {
		Pair<K, V> p = new Pair<K, V>(key, null);
		// siccome l'indexOf usa l'equals, e l'equals del Pair confronta solo le
		// keys, va bene.
		int index = indexOf(p);
		if (index == -1) // if not found
			return null;
		return list.get(index);
	}

	@Override
	public int indexOf(Object o) {
		return list.indexOf(o);
	}

	@Override
	public boolean isEmpty() {
		return list.isEmpty();
	}

	@Override
	public Iterator<Pair<K, V>> iterator() {
		return list.iterator();
	}

	public Set<K> keySet() {
		Set<K> set = new LinkedHashSet<K>();
		for (Pair<K, V> pair : list) {
			set.add(pair.getKey());
		}
		return set;
	}

	@Override
	public int lastIndexOf(Object o) {
		return list.lastIndexOf(o);
	}

	@Override
	public ListIterator<Pair<K, V>> listIterator() {
		return list.listIterator();
	}

	@Override
	public ListIterator<Pair<K, V>> listIterator(int index) {
		return list.listIterator(index);
	}

	public V put(K arg0, V arg1) {
		// TODO Auto-generated method stub
		return null;
	}

	public void putAll(Map<? extends K, ? extends V> arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public Pair<K, V> remove(int index) {
		return list.remove(index);
	}

	@Override
	public boolean remove(Object o) {
		return list.remove(o);
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		return list.removeAll(c);
	}

	@Override
	public boolean retainAll(Collection<?> c) {
		return list.retainAll(c);
	}

	@Override
	public Pair<K, V> set(int index, Pair<K, V> element) {
		return list.set(index, element);
	}

	/**
	 * Replaces the pair with the specified key in this list with the specified
	 * element (optional operation).
	 * 
	 * @param key
	 *            key of the pair to replace.
	 * @param element
	 *            element to be stored at the specified position.
	 * @return the element previously at the specified position.
	 */
	public Pair<K, V> set(K key, Pair<K, V> element) {
		return set(indexOf(element), element);
	}

	/**
	 * If there is alreasy a Pair with the given key, its value will ve
	 * overwritten Otherwise, a new Pair will be added.
	 * 
	 * @param key
	 * @param value
	 * @return the Pair with the given key
	 */
	public Pair<K, V> set(K key, V value) {
		Pair<K, V> newPair = new Pair<K, V>(key, value);
		if (!this.contains(newPair)) {
			this.add(newPair);
			return newPair;
		} else {
			newPair = this.getEntry(key);
			newPair.setValue(value);
			return newPair;
		}
	}

	@Override
	public int size() {
		return list.size();
	}

	@Override
	public List<Pair<K, V>> subList(int fromIndex, int toIndex) {
		return list.subList(fromIndex, toIndex);
	}

	@Override
	public Object[] toArray() {
		return list.toArray();
	}

	@Override
	public <T> T[] toArray(T[] a) {
		return list.toArray(a);
	}

	public Collection<V> values() {
		// TODO Auto-generated method stub
		return null;
	}

}
